home *** CD-ROM | disk | FTP | other *** search
/ Programming Sound Cards / Programming Sound Cards.iso / sound_56 / blaster.pas next >
Pascal/Delphi Source File  |  1995-01-01  |  42KB  |  1,179 lines

  1. {$A+,B-,D+,E-,F-,G+,I-,L+,N-,O-,P-,Q-,R-,S-,T-,V-,X+,Y+}
  2. {$M 16384,0,655360}
  3. Unit Blaster;
  4.  
  5. { -------------------------------------------------------------------- }
  6. { This is a specially for detecting and using the soundblaster card.   }
  7. { autodetect routines work for dsp adresses 210 to 280,                }
  8. { 8bit dmachannels 0,1,3/ 16bit dmachannel 5 and for interrupts 2,5,7  }
  9. { (known problems with IRQ2)                                           }
  10. { -------------------------------------------------------------------- }
  11. { no more work on autodetection - wait for craigs source, takes better }
  12. { advantage to our knowledge about different SB models, we got in last }
  13. { time. i.e. you can read IRQ#/DMA8/DMA16 from mixer port on SB16      }
  14. { --------------------------------------------------------------------- }
  15. { I read about 16Bit improvment for SB PRO3/4.0 but don't know about -  }
  16. { anybody can help me with that ?                                       }
  17. { how to use it ... any specifications for it ?                         }
  18. { --------------------------------------------------------------------- }
  19. { STATUS: TESTED ON SB16/ASP,SB PRO2,SB2.0                              }
  20. {         COMMENTs READY                                                }
  21. {   KNOWN PROBLEMS : - IRQ2 detection is wrong on some maschines        }
  22. {                    - no 16bit IRQ autodetection :(                    }
  23. {                    - no check if values are right in                  }
  24. {                               * UseBlasterEnv                         }
  25. {                               * InputBlasterValues                    }
  26. {                    - no mixedup detection (i.e. some values as        }
  27. {                      parameters and detect the rest)                  }
  28. {                      I though about this while I had a SB PRO and a   }
  29. {                      SB16 at the same time 'inside' on base 220h,240h }
  30. { --------------------------------------------------------------------- }
  31.  
  32. Interface
  33.  
  34. { the different SoundBlaster versions and its hardware : }
  35. {  0. - no soundblaster present
  36.    1. Soundblaster 1.0/1.5
  37.         23kHz(mono)                   8bit        no mixer
  38.  
  39.    2. Soundblaster Pro
  40.         45kHz(mono)    23kHz(stereo)  8bit        mixer
  41.  
  42.    3. Soundblaster 2.0/ Audioblaster 2.5
  43.         45kHz(mono)                   8bit        audiob. with mixer
  44.  
  45.    4. Soundblaster Pro3/Audioblaster Pro 4.0
  46.         45kHz(mono)    23kHz(stereo)  8bit        mixer
  47.  
  48.    5. Soundblaster Pro (Mircochannel)
  49.         Special version for PS/2 - technical data = 4
  50.  
  51.    6. Soundblaster 16/16ASP
  52.         45kHz(mono)    45kHz(stereo)  8/16bit        mixer
  53.  
  54.    DSP versions :
  55.  
  56.    SoundBlaster 1.0/1.5        1.xx
  57.    SoundBlaster 2.0/2.5        2.xx
  58.    SoundBlaster Pro/PRO3/PRO4  3.xx
  59.    SoundBlaster 16/ASP         4.xx
  60. }
  61.  
  62. CONST defaultvolume=31;    { full power =;) }
  63.       IRQ_TABLE:array[0..15] of byte = ($08,$09,$0a,$0B,$0C,$0D,$0E,$0F,
  64.                                         $70,$71,$72,$73,$74,$75,$76,$77);
  65.  
  66. VAR
  67.     stereo_possible:Boolean;    (* flag if stereo is possible on detected SB *)
  68.     _16Bit_possible:Boolean;    (* flag if 16bit play is possible on detected SB *)
  69.     maxstereorate:word;         (* max stereo samplerate on detected SB *)
  70.     maxmonorate:word;           (* max mono samplerate on detected SB *)
  71.  
  72.     Stereo:Boolean;             (* flag if stereo-play on/off *)
  73.     _16Bit:Boolean;             (* flag if 16bit-play on/off *)
  74.     SBNo:byte;                  (* SoundBlaster typ (look some rows above) *)
  75.     signeddata:boolean;         (* play signed data ? (only on SB16 possible) *)
  76.  
  77.     IRQ_No:Byte;                (* IRQ detected SB uses *)
  78.     DSP_Addr:Word;              (* Baseaddress detected SB uses *)
  79.     DMA_Channel:Byte;           (* DMA channel for 8 Bit play *)
  80.     DMA_16BitChannel:byte;      (* DMA channel for 16 Bit play *)
  81.  
  82. PROCEDURE Forceto(typ,dma,dma16,irq:byte;dsp:word);     (* force to use these values for playing *)
  83. FUNCTION UseBlasterEnv:boolean;                         (* use values set in enviroment BLASTER *)
  84. FUNCTION InputSoundblasterValues:Boolean;               (* Input Soundbaster values by hand (in textmode) *)
  85. FUNCTION DetectSoundblaster(prot:boolean):Boolean;      (* detects Soundblastercard *)
  86.  
  87. FUNCTION Detect_DSP_Addr(prot:boolean):Boolean;         (* detects DSP ADDR *)
  88. FUNCTION Detect_DMA_Channel_IRQ(prot:boolean):Boolean;  (* detects DMA Channel,DSPIRQ *)
  89. FUNCTION Get_BlasterVersion:Word;                       (* reads the detected soundblaster version *)
  90.  
  91. procedure check_samplerate(var rate:word;var stereo:boolean); (* check min/max samplerate *)
  92.  
  93. procedure set_DMAvalues(p:pointer;Length:word;autoinit:boolean);
  94.   (* config DMAcontroller for different transfer modes *)
  95. procedure play_firstBlock(length:word);
  96.   (* set the SBinterrupt to "interrupt" every "length" bytes
  97.      the best way to use it, is to play the half buffersize and then
  98.      write the new data in the allready played part
  99.      - you have to setup DMA controller by calling set_DMAvalues *)
  100. PROCEDURE play_oneBlock(p:pointer;length:word);
  101.   (* it's a play routine for playing only one buffer (NOT CONTINOUSLY
  102.      PLAYING ! - it does not work in that way on a SB16 !)
  103.      we use non autoinit mode here for all SBs...
  104.      this proc. setup DMA controller *)
  105. PROCEDURE Initblaster(var frequ:Word;stereoon,_16Biton:Boolean);
  106.   (* set frequency and stereo/mono and 8/16 Bit mode *)
  107.  
  108. PROCEDURE wr_mixerreg(reg,wert:byte);
  109.   (* writes something to the mixing chip *)
  110. FUNCTION  rd_mixerreg(reg:byte):byte;
  111.   (* reads something from the mixing chip *)
  112.  
  113. PROCEDURE set_ready_irq(p:pointer);
  114.   (* set user irq - (irq if buffer ends !)
  115.      attention look at my default irq !
  116.      You need those two port commands you'll find there !
  117.      And pay attention to 16bit/8bit mode on SB16 (different
  118.      ackknowledgement ports) *)
  119. PROCEDURE stop_play;         (* stops playing ! *)
  120. PROCEDURE pause_play;        (* stops playing, but you can continue
  121.                                 with "continue_play" *)
  122. PROCEDURE continue_play;     (* continues playing after pause play *)
  123. PROCEDURE restore_irq;       (* restore old interrupt vector *)
  124. PROCEDURE set_sign(signed:boolean); (* sets flag to play signed data
  125.                - does only work on SB16 (set it before start playing) *)
  126. PROCEDURE setvolume(vol:Byte);   (* what do you think ? *)
  127. PROCEDURE speaker_on;            (* Does not work on SB16 *)
  128. PROCEDURE speaker_off;
  129. procedure write_zaehler;         (* It's for 8 & 16 Bit mode to get the DMA counter *)
  130. function  get_zaehler:word;      (* It's for 8 & 16 Bit mode to get the DMA counter *)
  131. procedure writelnSBConfig;       (* what do you expect ? - write current setup to screen,
  132.                                     but detect SB before calling that proc. *)
  133.  
  134. Implementation
  135.  
  136. uses dos,crt;
  137.  
  138. { Flags and variables for detect part : }
  139. VAR SB_Detect:Boolean;              { Flag if SB is detected }
  140.     DSPIRQ_Detect:Boolean;          { Flag if IRQ number is detected }
  141.     DSPADR_Detect:Boolean;          { Flag if Baseaddress is detected }
  142.     DMACHN_Detect:Boolean;          { Flag if DMAchannel is detected }
  143.     MIXER_Detect:Boolean;           { Flag if Mixerchip is detected }
  144.     SBVersHi:Byte;                  { Soundblaster version major }
  145.     SBVersLo:Byte;                  { Soundblaster version minor }
  146.  
  147.     check:byte;                     { for detecting }
  148.     savvect:pointer;                {  "       "    }
  149.  
  150. { Soundblaster handling : }
  151.  
  152. function try_reset(p:word):Boolean; assembler;
  153.   asm
  154.         mov        bl,1
  155.         mov        dx,p
  156.         add        dx,6
  157.         mov        al,1         { write 1 to port 2x6 }
  158.         out        dx,al
  159.         in         al,dx
  160.         in         al,dx
  161.         in         al,dx
  162.         in         al,dx
  163.         xor        al,al
  164.         out        dx,al        { after 3,3 µs write 0 to port 2x6 }
  165.  
  166. { And now check the answer }
  167.         add        dx,8
  168.         mov        si,200
  169. @@readloop:
  170.         mov        cx,0ffffh      { SB2.0/1.0 are that slow :( }
  171. @@testl:                          { check for data available }
  172.         in         al,dx
  173.         dec        cx
  174.         jz         @@not
  175.         or         al,al
  176.         jns        @@testl
  177.  
  178.         sub        dx,4
  179.         in         al,dx        { read data comming through }
  180.         cmp        al,0aah
  181.         je         @@aSB
  182.         add        dx,4
  183.         dec        si
  184.         jnz        @@readloop
  185. @@not:  mov        bl,0         { it's not a SB :( }
  186. @@aSB:  xor        ah,ah
  187.         mov        al,bl
  188.   end;
  189.  
  190. procedure wr_dsp; assembler;
  191. { it's WAITWRITE and then WRITE IT }
  192.   asm
  193.         push      bx
  194.         push      cx
  195.         mov       bh,al
  196.         mov       dx,dsp_addr
  197.         add       dx,0ch
  198.         mov       cx,0ffffh        { ya know, slow SBs }
  199.         { Wait for writing : }
  200. @@litl: in        al,dx
  201.         dec       cx
  202.         jz        @@ende
  203.         or        al,al
  204.         js        @@litl  { check bit 7 if we can write to port 2xC }
  205.         mov       al,bh
  206.         out       dx,al   { write it }
  207. @@ende: pop       cx
  208.         pop       bx
  209.   end;
  210.  
  211. procedure speaker_off;
  212.   begin
  213.     asm
  214.       mov       al,0d3h
  215.       call      wr_dsp
  216.       push      220             { needs a bit time to switch it off }
  217.       call far ptr delay
  218.     end;
  219.   end;
  220.  
  221. procedure speaker_on;
  222.   begin
  223.     asm
  224.       mov       al,0d1h
  225.       call      wr_dsp
  226.       push      110             { needs a bit time to switch it on }
  227.       call far ptr delay
  228.       end;
  229.   end;
  230.  
  231. function rd_dsp:byte; assembler;
  232. { It's WAITREAD and then READ byte }
  233.   asm
  234.         mov       dx,dsp_addr
  235.         add       dx,0eh
  236.         mov       cx,0ffffh    { ya know - slow SBs. You can believe me ! }
  237.         { check for data available : }
  238. @@litl: in        al,dx
  239.         dec       cx
  240.         jz        @@ende
  241.         or        al,al
  242.         jns       @@litl   { bit 7 set ? if not then wait }
  243.         sub       dx,0eh-0ah
  244.         in        al,dx    { write data }
  245.         xor       ah,ah
  246. @@ende:
  247.   end;
  248.  
  249. procedure wr_mixerreg(reg,wert:byte); assembler;
  250. { this routine may not work for all registers because of different timings.}
  251.   asm
  252.     cmp       [SBNo],1
  253.     je        @@nomixer                   { SB 1.0/1.5 has no mixer ! }
  254.     cmp       SBNo,3
  255.     je        @@nomixer                   { SB 2.0/2.5 has no mixer ! }
  256.     mov       al,reg
  257.     mov       dx,dsp_addr
  258.     add       dx,4
  259.     out       dx,al
  260.     inc       dx
  261.     in        al,dx
  262.     mov       al,wert
  263.     out       dx,al
  264. @@nomixer:
  265.   end;
  266.  
  267. function rd_mixerreg(reg:byte):byte; assembler;
  268.   asm
  269.     cmp       [SBNo],1
  270.     je        @@nomixer                   { SB 1.0/1.5 has no mixer ! }
  271.     cmp       SBNo,3
  272.     je        @@nomixer                   { SB 2.0/2.5 has no mixer ! }
  273.     mov     dx,dsp_addr
  274.     add     dx,4
  275.     mov     al,reg
  276.     out     dx,al
  277.     inc     dx
  278.     in      al,dx
  279.     xor     ah,ah
  280. @@nomixer:
  281.   end;
  282.  
  283. { Sorry no cool macro like in C is possible }
  284. function loword(l:longint):word; assembler;
  285.   asm
  286.     mov         ax,word ptr(l)
  287.   end;
  288.  
  289. function hiword(l:longint):word; assembler;
  290.   asm
  291.     mov         ax,word ptr(l+2)
  292.   end;
  293.  
  294. procedure set_DMAvalues(p:pointer;Length:word;autoinit:boolean);
  295. { If you want to know more about how to setup DMA controller, please
  296.   refer to our documentation SBLASTER.ZIP. }
  297. const pagetable:array[0..7] of word = ($0087  { channel 0 },
  298.                                        $0083  { channel 1 },
  299.                                        $0081  { channel 2 <- not used by SB },
  300.                                        $0082  { channel 3 },
  301.                                        $008F  { channel 4 <- not used by SB },
  302.                                        $008B  { channel 5 },
  303.                                        $0089  { channel 6 },
  304.                                        $008A  { channel 7 });
  305.   begin
  306.     asm
  307.                 { start : }
  308.                 cmp       [_16Bit],1      { setup 16bit DMA channels 4..7 is
  309.                                             ab bit different }
  310.                 je        @@higherDMA
  311.                 { first the SBPRO stereo bugfix : }
  312.                 cmp       [stereo],0
  313.                 je        @@nostereo
  314.                 cmp       [sbNo],6
  315.                 jae       @@sbhigher
  316.                 { well ... should be a SB PRO in stereo mode ... }
  317.                 { let's send one byte ! }
  318.                 mov       al,10h
  319.                 call      wr_dsp
  320.                 mov       al,128   { nothin but silence ! }
  321.                 call      wr_dsp
  322. @@sbhigher:
  323. @@nostereo:
  324.                 { convert pointer in realadress :
  325.                   dmapage*65536+dmaoffset = memsegment*16 + memoffset }
  326.                 mov       ax,word ptr(p+2)
  327.                 rol       ax,4
  328.                 mov       cl,al
  329.                 and       al,0f0h
  330.                 and       cl,0fh
  331.                 mov       di,ax         { cl:di - realadress ! }
  332.  
  333.                 mov       bh,dma_channel { bh with dma_channel }
  334.                 mov       bl,bh
  335.                 shl       bl,1          { bl with dma_channel*2 }
  336.                 mov       ch,048h       { ch = 010010xx }
  337.                                          {     \| |+- read
  338.                                                 | +- autoinit flag
  339.                                                 +- singlemode }
  340.                 mov     al,[autoinit]
  341.                 shl     al,4
  342.                 or      ch,al              { set the autoinit flag }
  343.                 add     ch,dma_channel     { prepare for dma_channel }
  344.  
  345.                 mov     al,4
  346.                 add     al,bh           { bh = dma_channel }
  347.                 out     0ah,al          { mask the channel }
  348.  
  349.                 xor     al,al
  350.                 out     0ch,al          { clear flipflop }
  351.  
  352.                 mov     al,ch           { ch = DMAmode }
  353.                 out     0bh,al          { set dmatransfer mode }
  354.                 mov     ax,di           { di = DMAbuffer offset }
  355.                 push    bx
  356.                 xor     bh,bh
  357.                 mov     dx,bx           { bx = 2*dma_channel }
  358.                 out     dx,al           { lower adress }
  359.                 mov     al,ah
  360.                 out     dx,al           { higer adress }
  361.                 mov     dx,word ptr (pagetable+bx)
  362.                 mov     al,cl           { cl = DMAbuffer page }
  363.                 out     dx,al           { data page }
  364.                 mov     dx,bx           { bx = 2*dma_channel }
  365.                 mov     ax,Length
  366.                 dec     ax
  367.                 inc     dx              { dx = write base count }
  368.                 out     dx,al           { write lower length }
  369.                 mov     al,ah
  370.                 out     dx,al           { write higer length }
  371.                 pop     bx
  372.                 mov     al,dma_channel
  373.                 out     0ah,al          { demask channel }
  374.                 jmp     @@endofsetauto
  375. @@higherDMA:    { jump to here if 16bit DMA setup }
  376.                 { convert pointer in realadress : }
  377.                 mov       ax,word ptr(p+2)      { ax = segment of buffer }
  378.                 rol       ax,4                  { attention no offset ! }
  379.                 mov       cl,al
  380.                 and       al,0f1h
  381.                 and       cl,00eh
  382.                 ror       ax,1
  383.                 mov       di,ax                 { cl:di - realadress ! }
  384.  
  385.                 mov     bh,dma_16Bitchannel     { bh with dma_channel }
  386.                 sub     bh,4                    { channel 4-7 to number 0-3 }
  387.                 mov     bl,bh
  388.                 shl     bl,2
  389.                 add     bl,0c0h       { bl = DMA adressport for current DMAchannel }
  390.                                       { bh = DMA16Bitchannel - 4  (0..3) }
  391.                 mov     ch,048h       { ch = 010010xx }
  392.                                        {     \| |+-read
  393.                                               | +-autoinitflag
  394.                                               +-singlemode }
  395.                 mov     al,[autoinit]
  396.                 shl     al,4
  397.                 or      ch,al          { set the autoinitflag }
  398.                 add     ch,bh          { ch = command for DMAchannel # }
  399.  
  400.                 mov     al,4
  401.                 add     al,bh           { bh = 16bitDMA_channel - 4 }
  402.                 out     0d4h,al         { mask the channel }
  403.                 xor     al,al
  404.                 out     0d8h,al         { clear flipflop }
  405.                 mov     al,ch           { ch = dmamode }
  406.                 out     0d6h,al         { set dmatransfer mode }
  407.                 mov     ax,di           { lower part of adress }
  408.                 push    bx
  409.                 xor     bh,bh           { bx now = c0h/c4h/c8h/cch (0..3) }
  410.                 mov     dx,bx           { bx = addressport for current channel }
  411.                 out     dx,al           { write lower adress }
  412.                 mov     al,ah
  413.                 out     dx,al           { write higer adress }
  414.                 mov     dl,dma_16Bitchannel
  415.                 xor     dh,dh
  416.                 mov     si,dx           { si = dma16Bitchannel }
  417.                 shl     si,1            { si - position in pagetable }
  418.                 mov     dx,word ptr (pagetable+si)
  419.                 mov     al,cl           { dmabuffer page }
  420.                 out     dx,al           { data page }
  421.                 mov     dx,bx           { old dx value ;) c0h/c4h/c8h/cch }
  422.                 mov     ax,Length
  423.                 dec     ax
  424.                 add     dx,2            { seperated by 2 -> dx now DMA base count }
  425.                 out     dx,al           { write lower length }
  426.                 mov     al,ah
  427.                 out     dx,al           { write higer length }
  428.                 pop     bx
  429.                 mov     al,bh
  430.                 out     0d4h,al         { demask channel }
  431. @@endofsetauto:
  432.   end;
  433. end;
  434.  
  435. function get_zaehler:word; assembler;
  436. { get the dma base counter of dmachannel is used by SB
  437.   you can check if sound transfer does work ;) }
  438.     asm
  439.        cmp      [_16Bit],1
  440.        je       @@get16
  441.        xor      al,al
  442.        out      0ch,al           { clear flipflop }
  443.        mov      dl,dma_channel
  444.        xor      dh,dh
  445.        shl      dx,1
  446.        inc      dx               { dx = channel * 2 + 1 = base counter }
  447.        in       al,dx            { al = lower byte }
  448.        mov      bl,al
  449.        in       al,dx            { al = higher byte }
  450.        mov      bh,al
  451.        mov      ax,bx            { AX = high and low part together ;) - return that }
  452.                                  { bytes left to send = ax + 1 }
  453.        jmp      @@endofget
  454. @@get16:
  455.        xor      al,al
  456.        out      0d8h,al           { clear flipflop }
  457.        mov      dl,dma_16Bitchannel
  458.        xor      dh,dh
  459.        sub      dl,4              { channel 4..7 to number 0..3 }
  460.        shl      dx,2
  461.        add      dx,0c2h           { dx = 0c2h + 4 * (channel-4) = 16bit base counter }
  462.        in       al,dx             { AL = lower part }
  463.        mov      bl,al
  464.        in       al,dx             { AL = higher part }
  465.        mov      bh,al
  466.        mov      ax,bx             { AX = 16bit value ;) -
  467.                                     number WORDS (!) left to send = ax + 1 }
  468. @@endofget:
  469.     end;
  470.  
  471. procedure write_zaehler;
  472. { A stupid function I know, but get_zaehler did not exist in testphase
  473.   of my player, that was all in write_zaehler implemented, but later I
  474.   thought it would be usefull to implement get_zaehler for debugging. }
  475.   begin
  476.     write(' ',get_zaehler,' ');
  477.   end;
  478.  
  479. procedure play_firstBlock(length:word);
  480. { call this if you want to do continues play }
  481.   begin
  482.     asm
  483.                 cmp       [SBNo],6
  484.                 je        @@sb16init          { use special commands on SB16 }
  485.  
  486.                 mov       bl,90h              { DSP 90h - autoinit highspeed DMA }
  487.                 cmp       [SBNo],1
  488.                 jne       @@highspeed         { >SB1.0 use highspeed modes }
  489.                 { for SB1.0 : }
  490.                 mov       bl,1ch              { DSP 1Ch - autoinit normal DMA }
  491. @@highspeed:
  492.                 mov       cx,length
  493.                 dec       cx
  494.                 mov       al,048h             { DSP 48h - setup DMA buffer size }
  495.                 call      wr_dsp
  496.                 mov       al,cl               { lower part of size }
  497.                 call      wr_dsp
  498.                 mov       al,ch               { higher part of size }
  499.                 call      wr_dsp
  500.                 mov       al,bl               { DSP command depends on SB }
  501.                 call      wr_dsp
  502.                 jmp       @@ende
  503.  
  504. @@sb16init:     mov       cx,length
  505.                 dec       cx
  506.                 cmp       [_16Bit],1          { other command for 16bit play ... }
  507.                 je        @@play16Bit
  508.                 mov       al,0c6h             { DSP c6h - use 8bit autoinit }
  509.                 call      wr_dsp
  510.                 mov       al,signeddata
  511.                 shl       al,4                { 2nd command byte: bit 4 = 1 - signed data }
  512.                 cmp       [stereo],0
  513.                 je        @@nostereo
  514.                 or        al,020h             { 2nd command byte: bit 5 = 1 - stereo data }
  515. @@nostereo:     call      wr_dsp              { write 2nd command byte }
  516.                 mov       al,cl               { lower part of size }
  517.                 call      wr_dsp
  518.                 mov       al,ch               { higher part of size }
  519.                 call      wr_dsp
  520.                 jmp       @@ende
  521. @@play16Bit:    mov       al,0B6h             { DSP B6h - use 16bit autoinit }
  522.                 call      wr_dsp
  523.                 mov       al,signeddata
  524.                 shl       al,4                { 2nd command byte: bit 4 = 1 - signed data }
  525.                 cmp       [stereo],0
  526.                 je        @@nostereo2
  527.                 or        al,020h             { 2nd command byte: bit 5 = 1 - stereo data }
  528. @@nostereo2:    call      wr_dsp              { write 2nd command byte }
  529.                 mov       al,cl               { lower part of size }
  530.                 call      wr_dsp
  531.                 mov       al,ch               { higher part of size }
  532.                 call      wr_dsp
  533. @@ende:
  534.     end;
  535.   end;
  536.  
  537. PROCEDURE play_oneBlock(p:pointer;length:word);
  538. { call this if you want to play only ONE (!) block - I'm sure you can do
  539.   continues play with this proc. on SBs <SB16 (I have seen that often in
  540.   other sources, but it'll definitly not work on a SB16 ! It'll cause
  541.   'ticks' }
  542.   begin
  543.     set_DMAvalues(p,length,false);
  544.     asm
  545.                 
  546.                 cmp       [SBNo],6
  547.                 je        @@sb16init          { use special commands on SB16 }
  548.  
  549.                 mov       bl,91h              { DSP 91h - nonautoinit highspeed DMA }
  550.                 cmp       [SBNo],1
  551.                 je        @@highspeed         { >SB1.0 use highspeed mode }
  552.                 { On SB1.0 : }
  553.                 mov       bl,14h              { DSP 14h - nonautoinit normal DMA }
  554. @@highspeed:
  555.                 mov       cx,length
  556.                 dec       cx
  557.                 mov       al,048h             { DSP 48h - setup DMA buffer size }
  558.                 call      wr_dsp
  559.                 mov       al,cl               { lower part of size }
  560.                 call      wr_dsp
  561.                 mov       al,ch               { higher part of size }
  562.                 call      wr_dsp
  563.                 mov       al,bl               { DSP command depends on SB }
  564.                 call      wr_dsp
  565.                 jmp       @@ende
  566.  
  567. @@sb16init:     mov       cx,length
  568.                 dec       cx
  569.                 cmp       [_16Bit],1          { other command for 16bit play ... }
  570.                 je        @@play16Bit
  571.                 mov       al,0c2h             { DSP c2h - use 8bit nonautoinit }
  572.                 call      wr_dsp
  573.                 mov       al,signeddata
  574.                 shl       al,4                { 2nd command byte: bit 4 = 1 - signed data }
  575.                 cmp       [stereo],0
  576.                 je        @@nostereo
  577.                 or        al,020h             { 2nd command byte: bit 5 = 1 - stereo data }
  578. @@nostereo:     call      wr_dsp              { write 2nd command byte }
  579.                 mov       al,cl               { lower part of size }
  580.                 call      wr_dsp
  581.                 mov       al,ch               { higher part of size }
  582.                 call      wr_dsp
  583.                 jmp       @@ende
  584. @@play16Bit:    mov       al,0B2h             { DSP B2h - use 16bit nonautoinit }
  585.                 call      wr_dsp
  586.                 mov       al,signeddata
  587.                 shl       al,4                { 2nd command byte: bit 4 = 1 - signed data }
  588.                 cmp       [stereo],0
  589.                 je        @@nostereo2
  590.                 or        al,020h             { 2nd command byte: bit 5 = 1 - stereo data }
  591. @@nostereo2:    call      wr_dsp              { write 2nd command byte }
  592.                 mov       al,cl               { lower part of size }
  593.                 call      wr_dsp
  594.                 mov       al,ch               { higher part of size }
  595.                 call      wr_dsp
  596. @@ende:
  597.     end;
  598.   end;
  599.  
  600. { -------------------- continue commenting here ---------------------- }
  601.  
  602. PROCEDURE SetTimeConst(tc:byte);
  603. { Setup samplerate with time constant, take this :
  604.   TC = 256- TRUNC(1000000/SAMPLERATE) }
  605.   begin
  606.     asm
  607.       mov       al,040h
  608.       call      wr_dsp
  609.       mov       al,tc
  610.       call      wr_dsp
  611.     end;
  612.   end;
  613.  
  614. PROCEDURE Initblaster(var frequ:Word;stereoon,_16Biton:boolean);
  615. { Initblaster does this :   1. check samplerates for its borders
  616.                             2. Reset DSP chip
  617.                             3. setup samplerate
  618.                             4. setup stereo/mono mode
  619.  if you want to play signed data on SB16, call 'set_sign' after Initblaster }
  620.  
  621. var tc:byte;
  622.     w:word;
  623.   begin
  624.     { first reset SB : }
  625.     asm
  626.       mov    dx,dsp_addr
  627.       add    dx,0eh
  628.       in     al,dx
  629.       inc    dx
  630.       in     al,dx
  631.     end;
  632.     stop_play;
  633.     { Now init : }
  634.     check_samplerate(frequ,stereoon);
  635.     _16bit:=(SBNo=6) and _16Biton;
  636.     stereo:=stereoon;
  637.     { calculate timeconstant - pay attention on SB PRO you have to setup
  638.       2*samplerate in stereo mode (so call it byterate) - on SB16 not ! }
  639.     if (sbno=6) or not stereo then
  640.       begin
  641.         tc:=256-1000000 div frequ;
  642.         frequ:=1000000 div (256-tc);
  643.       end
  644.     else
  645.       begin
  646.         tc:=256-1000000 div (2*frequ);
  647.         frequ:=(1000000 div (256-tc)) div 2;
  648.       end;
  649.     w:=frequ;
  650.     try_reset(dsp_addr);
  651.     { set sampling rate }
  652.     if (sbno<6) then
  653.     asm
  654.        { on all normal SB's :) }
  655.        mov      al,040h
  656.        call     wr_dsp
  657.        mov      al,tc
  658.        call     wr_dsp
  659.     end
  660.     else
  661.     asm
  662.        { on SB16 }
  663.        mov      al,041h
  664.        call     wr_dsp
  665.        mov      ax,w
  666.        xchg     al,ah
  667.        call     wr_dsp
  668.        mov      al,ah
  669.        call     wr_dsp
  670.     end;
  671.     { setup stereo option on SB PRO - on SB16 it's set in DSP command }
  672.     if stereo and (SBNo<>6) then
  673.       wr_mixerreg($0e,rd_mixerreg($0e) or $02); { stereo option on (only SB PRO) }
  674.     if SBNo in [2,4,5] then
  675.       wr_mixerreg($0e,rd_mixerreg($0e) or $20); { filter option off (only SB PRO) }
  676.     speaker_on;
  677.   end;
  678.  
  679. { -------------- now the procedures for my old autodetection ------------- }
  680. { No comments about it - it's old ;)                                       }
  681. procedure irq2;interrupt;var a:byte; begin check:=2;port[$20]:=$20;a:=port[dsp_addr+$0e] end;
  682. procedure irq5;interrupt;var a:byte; begin check:=5;port[$20]:=$20;a:=port[dsp_addr+$0e] end;
  683. procedure irq7;interrupt;var a:byte; begin check:=7;port[$20]:=$20;a:=port[dsp_addr+$0e] end;
  684. procedure ready_irq; interrupt;var a:byte; begin check:=1;port[$20]:=$20;a:=port[dsp_addr+$0e] end;
  685.  
  686. function hexword(w:word):string;
  687. const hex:string= '0123456789ABCDEF';
  688.   begin
  689.    hexword:=hex[hi(w) div 16+1]+hex[hi(w) mod 16+1]+hex[lo(w) div 16+1]+hex[lo(w) mod 16+1];
  690.   end;
  691.  
  692. FUNCTION Detect_DSP_Addr(prot:boolean):Boolean;
  693. var p:word;
  694.   begin
  695.     if dspadr_detect then begin detect_dsp_addr:=true; exit end;
  696.     if prot then writeln(' Now locating DSP-Adresse :'#13#10);
  697.     detect_dsp_addr:=false;
  698.     p:=$210;
  699.     while not dspadr_detect and (p<$290) do
  700.       begin
  701.         if prot then write(' Trying ',hexword(p),' .... ');
  702.         dspadr_detect:=try_reset(p);
  703.         if not dspadr_detect then
  704.           begin
  705.             inc(p,$10);
  706.             if prot then write('not ');
  707.           end;
  708.         if prot then writeln('succesfull ');
  709.       end;
  710.     if not dspadr_detect then exit;
  711.     dsp_addr:=p;
  712.     detect_dsp_addr:=true;
  713.   end;
  714.  
  715. PROCEDURE reset_mixer;
  716.   begin
  717.     asm
  718.       mov    dx,dsp_addr
  719.       add    dx,4
  720.       mov    al,0
  721.       out    dx,al
  722.       mov    cx,50
  723. @@loop: loop @@loop
  724.       inc    dx
  725.       inc    al
  726.       out    dx,al
  727.     end;
  728.   end;
  729.  
  730. FUNCTION Detect_DMA_Channel_IRQ(prot:boolean):Boolean;
  731. const irqs:array[1..3] of byte = (10,13,15); (* IRQ 2,5,7 *)
  732. var oldv:array[1..5] of pointer;
  733.     i,nr:byte;
  734.     fr:word;
  735.     ov1,ov2:byte;
  736.   begin
  737.     asm
  738.       mov al,0ffh
  739.       out 0fh,al
  740.       sti
  741.     end;
  742.     if dmachn_detect then begin detect_DMA_Channel_irq:=true;exit end;
  743.     if prot then writeln(#13#10' Now locating DMA-channel and IRQ :'#13#10);
  744.     detect_dma_channel_irq:=false;
  745.     if not dspadr_detect then exit;
  746.     for i:=1 to 3 do
  747.       begin
  748.         getintvec(irqs[i],oldv[i]);
  749.       end;
  750.     setintvec(10,addr(irq2));
  751.     setintvec(13,addr(irq5));
  752.     setintvec(15,addr(irq7));
  753.     Detect_DMA_Channel_irq:=false;
  754.     port[$21]:=port[$21] and $5F;  { 01011111b = 05Fh }
  755.     nr:=0;
  756.     while (nr<4) and not DMACHN_Detect do
  757.       begin
  758.         if prot then write(' Trying Channel ',nr,' .... ');
  759.         Check:=0;
  760.         DMA_Channel:=nr;
  761.         fr:=10000;
  762.         asm
  763.           mov al,dma_channel        { mask channel - means stop transfer }
  764.           out 0ah,al
  765.         end;
  766.         stop_play;speaker_off;
  767.         Initblaster(fr,false,false);
  768.         play_oneblock(ptr(0,0),1);
  769.         delay(10);
  770.         DMACHN_Detect:=check<>0;
  771.         if not DMACHN_Detect then
  772.           begin
  773.             inc(nr);if nr=2 then nr:=3;
  774.             if prot then write('not ');
  775.           end;
  776.         if prot then
  777.           begin
  778.             write('sucessful');
  779.             if DMACHN_Detect then writeln(' with Interrupt ',IRQ_Table[check],' - IRQ ',check)
  780.             else writeln;
  781.           end;
  782.       end;
  783.     port[$21]:=port[$21] or $A0;  { 10100000b = 0A0h }
  784.     for i:=1 to 3 do
  785.       setintvec(irqs[i],oldv[i]);
  786.     if not dmachn_detect then exit;
  787.     Detect_DMA_Channel_irq:=true;
  788.     DSPIRQ_detect:=true;
  789.     IRQ_no:=Check;
  790.     try_reset(dsp_addr);
  791.   end;
  792.  
  793. procedure Fix_blastertype;
  794.   var b1,b2:byte;
  795.   begin
  796.     asm
  797.       mov       al,0E1h        { DSP E1h - get DSP version }
  798.       call      wr_dsp
  799.     end;
  800.     sbversHi:=rd_dsp;
  801.     sbversLo:=rd_dsp;
  802.   end;
  803.  
  804. FUNCTION DetectSoundblaster(prot:boolean):Boolean;
  805.   begin
  806.     SBNo:=0;
  807.     DetectSoundblaster:=false;
  808.     SB_Detect:=False;
  809.     DSPIRQ_Detect:=false;
  810.     DSPADR_Detect:=false;
  811.     DMACHN_Detect:=False;
  812.     MIXER_Detect:=False;
  813.     stereo_possible:=false;
  814.     _16Bit_possible:=false;
  815.     STEREO:=False;_16Bit:=False;
  816.     if not Detect_DSP_Addr(prot) then
  817.       begin
  818.         if prot then writeln(' Can'#39't locate DSP-addresse ! ');
  819.         exit;
  820.       end;
  821.     fix_blastertype;
  822.  
  823.     if (sbversHi<1) or (sbversHi>4) then
  824.       begin
  825.         if prot then writeln(' Sorry, unknown DSP chip version on this base address detected.');
  826.         SBno:=0;
  827.         exit;
  828.       end;
  829.     { for the first set SB1.0 - should work on all SBs }
  830.     SBNo:=1;stereo_possible:=false;_16Bit_possible:=false;
  831.     maxmonorate:=22050;maxstereorate:=0;
  832.     stop_play;
  833.     if not Detect_DMA_Channel_irq(prot) then
  834.       begin
  835.         if prot then writeln(' Can'#39't locate DMA-channel and IRQ ! ');
  836.         sbNo:=0;
  837.         exit;
  838.       end;
  839.  
  840.     try_reset(dsp_addr);
  841.  
  842. {                              SBvers:
  843.    SoundBlaster 1.0/1.5        1.xx
  844.    SoundBlaster 2.0/2.5        2.xx
  845.    SoundBlaster Pro/PRO3/PRO4  3.xx
  846.    SoundBlaster 16/ASP         4.xx
  847. }
  848.     case sbversHi of
  849.       1: begin
  850.            SBNo:=1;stereo_possible:=false;_16Bit_possible:=false;
  851.            maxmonorate:=22050;maxstereorate:=0
  852.          end;
  853.       2: begin
  854.            SBNo:=3;stereo_possible:=false;_16Bit_possible:=false;
  855.            maxmonorate:=44100;maxstereorate:=0
  856.          end;
  857.       3: begin
  858.            SBNo:=2;stereo_possible:=true;_16Bit_possible:=false;
  859.            maxmonorate:=44100;maxstereorate:=22700
  860.          end;
  861.       4: begin
  862.            SBNo:=6;stereo_possible:=true;_16Bit_possible:=true;
  863.            maxmonorate:=45454;maxstereorate:=45454
  864.          end;
  865.       else begin SBNo:=0;exit end;
  866.     end;
  867.  
  868.     DetectSoundblaster:=true;
  869.   end;
  870.  
  871. FUNCTION Get_BlasterVersion:Word;
  872.   begin
  873.     Get_BlasterVersion:=word(SBVersHi)*256+SBVersLo;
  874.   end;
  875.  
  876. PROCEDURE set_ready_irq(p:pointer);
  877. var b:byte;
  878.   begin
  879.     check:=0;
  880.     getintvec(IRQ_Table[irq_no],savvect);
  881.     if p=Nil then p:=addr(ready_irq);
  882.     setintvec(IRQ_Table[irq_no],p);
  883.     b:=1 shl irq_no;b:=b or 04; { no changes for IRQ2 }
  884.     port[$21]:=port[$21] and not b; { masking ... }
  885.   end;
  886.  
  887. PROCEDURE restore_irq;
  888. var b:byte;
  889.   begin
  890.     b:=1 shl irq_no;b:=b and not 4; { no mask for IRQ2 }
  891.     port[$21]:=port[$21] or b;
  892.     setintvec(IRQ_Table[irq_no],savvect);
  893.   end;
  894.  
  895. FUNCTION ready:boolean;
  896.   begin
  897.     ready:=check>0;
  898.   end;
  899.  
  900. PROCEDURE stop_play;
  901.   begin
  902.     { for 16bit modes : }
  903.     asm
  904.       mov   al,0d0h
  905.       call  wr_dsp
  906.       mov   al,0d9h
  907.       call  wr_dsp
  908.       mov   al,0d0h
  909.       call  wr_dsp
  910.     end;
  911.     { for 8bit modes : }
  912.     asm
  913.       mov   al,0d0h
  914.       call  wr_dsp
  915.       mov   al,0dah
  916.       call  wr_dsp
  917.       mov   al,0d0h
  918.       call  wr_dsp
  919.     end;
  920.     try_reset(dsp_addr);   { reset is the best way to make sure SB stops playing ! }
  921.     asm
  922.       mov   al,dma_channel
  923.       out   0ah,al
  924.     end;
  925.   end;
  926.  
  927. PROCEDURE pause_play;
  928.   begin
  929.     if not _16bit then
  930.     asm
  931.       mov        al,0D0h
  932.       call       wr_dsp
  933.     end
  934.     else
  935.     asm
  936.       mov        al,0D5h
  937.       call       wr_dsp
  938.     end
  939.   end;
  940.  
  941. PROCEDURE continue_play;
  942.   begin
  943.     if not _16bit then
  944.     asm
  945.       mov        al,0D4h
  946.       call       wr_dsp
  947.     end
  948.     else
  949.     asm
  950.       mov        al,0D6h
  951.       call       wr_dsp
  952.     end
  953.   end;
  954.  
  955. PROCEDURE set_sign(signed:boolean);
  956.   begin
  957.     signeddata:=signed;
  958.   end;
  959.  
  960. procedure setfilter(how:boolean);
  961. var b:byte;
  962.   begin
  963.     b:=rd_mixerreg($0e);
  964.     if how then { on } b:=b or $20 else b:=b and not $20;
  965.     wr_mixerreg($0e,b); { switch the filter option }
  966.   end;
  967.  
  968. procedure setvolume(vol:byte);
  969. var b:byte;
  970.   begin
  971.     if sbno<6 then
  972.       begin
  973.         if vol>=15 then vol:=15;
  974.         b:=vol;
  975.         b:=b shl 4;        { the other side }
  976.         vol:=b+vol;
  977.         wr_mixerreg($22,vol);
  978.         wr_mixerreg($04,vol);
  979.       end
  980.     else
  981.       begin
  982.         { on SB16 the new mixer registers :) }
  983.         wr_mixerreg($30,vol);  { master left }
  984.         wr_mixerreg($31,vol);  { master right }
  985.         wr_mixerreg($32,vol);  { Voice left }
  986.         wr_mixerreg($33,vol);  { Voice right }
  987.       end;
  988.   end;
  989.  
  990. PROCEDURE Forceto(typ,dma,dma16,irq:byte;dsp:word);
  991.   begin
  992.     SB_Detect:=true;
  993.     DSPIRQ_Detect:=true;
  994.     DSPADR_Detect:=true;
  995.     DMACHN_Detect:=true;
  996.     stereo:=false;
  997.     _16Bit:=false;
  998.  
  999.     MIXER_detect:=typ>1;
  1000.     stereo_possible:=typ in [2,4,5,6];
  1001.     _16Bit_possible:= typ=6;
  1002.     IRQ_No:=irq;
  1003.     DSP_Addr:=dsp;
  1004.     DMA_Channel:=DMA;
  1005.     DMA_16BitChannel:=dma16;
  1006.     SBNo:=typ;
  1007.     case typ of
  1008.       1: begin maxmonorate:=22050;maxstereorate:=0 end;
  1009.       2: begin maxmonorate:=44100;maxstereorate:=22050 end;
  1010.       3: begin maxmonorate:=44100;maxstereorate:=0 end;
  1011.       4: begin maxmonorate:=44100;maxstereorate:=22050 end;
  1012.       5: begin maxmonorate:=44100;maxstereorate:=22050 end;
  1013.       6: begin maxmonorate:=45454;maxstereorate:=45454 end;
  1014.     end;
  1015.   end;
  1016.  
  1017. function UseBlasterEnv:boolean;
  1018. var s:string;
  1019.     typ,dma,dma16,irq:byte;
  1020.     dsp:word;
  1021.   function upstr(s:string):string;
  1022.     var t:string;
  1023.         i:byte;
  1024.     begin
  1025.       t:='';
  1026.       for i:=1 to length(s) do
  1027.         t:=t+upcase(s[i]);
  1028.       upstr:=t;
  1029.     end;
  1030.  
  1031. var count,i:byte;
  1032.     u:string;
  1033.     er:integer;
  1034.  
  1035.   begin
  1036.     typ:=255;dma:=255;dma16:=255;irq:=255;dsp:=$ffff;
  1037.     { default values (totally crap), but if you get them after calling Use....}
  1038.     { you'll know that this value is not/wrong defined in the BLASTER env. }
  1039.     UseBlasterEnv:=false;
  1040.     s:=upstr(getenv('BLASTER'));
  1041.     if s='' then exit; { no chance :( }
  1042.     count:=0;
  1043.     { SET BLASTER=A220 I? D? H? P??? T? }
  1044.     i:=pos('T',s); { Soundblaster typ }
  1045.     if i>0 then
  1046.       begin
  1047.         u:=copy(s,i+1,1); { maybe for future blaster versions not right :( }
  1048.         val(u,typ,er);
  1049.         if er=0 then inc(count); { yeah we got this value ! }
  1050.       end;
  1051.     i:=pos('D',s); { DMAchannel }
  1052.     if i>0 then
  1053.       begin
  1054.         u:=copy(s,i+1,1);
  1055.         val(u,dma,er);
  1056.         if (er=0) and (dma<4) and (dma<>2) then inc(count) { yeah we got it ! }
  1057.           else dma:=255;
  1058.       end;
  1059.     i:=pos('I',s); { IRQ number }
  1060.     if i>0 then
  1061.       begin
  1062.         if s[i+2]<>' ' then u:=copy(s,i+1,2) else u:=copy(s,i+1,1);
  1063.         val(u,irq,er);
  1064.         if (er=0) and ((irq=2) or (irq=5) or (irq=7) or (irq=10)) then inc(count)
  1065.           else irq:=255;
  1066.       end;
  1067.     i:=pos('H',s); { 16Bit DMAchannel }
  1068.     if i>0 then
  1069.       begin
  1070.         u:=copy(s,i+1,1);
  1071.         val(u,dma16,er);
  1072.         if (er<>0) or (dma16<5) or (dma16>9) then dma16:=255;
  1073.         { it does not matter if there's no value }
  1074.       end;
  1075.     i:=pos('A',s); { DSPadress }
  1076.     if i>0 then
  1077.       begin
  1078.         u:=copy(s,i+1,3);
  1079.         val(u,dsp,er);
  1080.         dsp:=(dsp div 100)*256+ ((dsp div 10) mod 10)*16 + dsp mod 10;
  1081.         if (er=0) and (dsp div 256 = 2) and (((dsp mod 256) div 16) in [2,3,4,5,6,7,8]) then inc(count)
  1082.           else dsp:=$ffff;
  1083.       end;
  1084.  
  1085.     if count=4 then { we got all :) }
  1086.       forceto(typ,dma,dma16,irq,dsp)
  1087.     else exit; { was not enough detectable }
  1088.     UseBlasterEnv:=true;
  1089.   end;
  1090.  
  1091. procedure writelnSBConfig;
  1092.   begin
  1093.     writeln(#13#10' Soundblaster typ: ');
  1094.     case sbNo of
  1095.       0: writeln(' none ');
  1096.       1: writeln(' Soundblaster 1.0/1.5 (8 bit/mono-max 24kHz)');
  1097.       2: writeln(' Soundblaster Pro (8 bit/mono-max 44kHz/stereo-max 22kHz)');
  1098.       3: writeln(' Soundblaster 2.0/2.5/junior (8 bit/mono-max 44kHz)');
  1099.       4: writeln(' Soundblaster Pro3.0/PRO 4.0 (8 bit/mono-max 44kHz/stereo-max 22kHz)');
  1100.       5: writeln(' Soundblaster Pro<microchannel> (8 bit/mono-max 44kHz/stereo-max 22kHz)');
  1101.       6: writeln(' Soundblaster 16/16 ASP (8/16 bit/mono/stereo/max 45kHz)');
  1102.     end;
  1103.     write(#13#10' SB-Base : 2');write((dsp_addr div 16) mod 16);writeln('0h');
  1104.     writeln(' 8bit DMA : ',dma_channel);
  1105.     if SBNo=6 then writeln(' 16bit DMA : ',dma_16Bitchannel);
  1106.     writeln(' IRQ : ',IRQ_No,#13#10);
  1107.   end;
  1108.  
  1109. FUNCTION InputSoundblasterValues:Boolean;
  1110. var c:char;
  1111.   begin
  1112.     InputSoundblasterValues:=false;
  1113.     writeln(#13#10' Soundblaster typ ? ');
  1114.     writeln(' 0) none ');
  1115.     writeln(' 1) Soundblaster 1.0/1.5                   .....  8 bit mono   (max 24kHz)');
  1116.     writeln(' 2) Soundblaster 2.0/2.5/junior            .....  8 bit mono   (max 44kHz)');
  1117.     writeln(' 3) Soundblaster Pro/Pro3.0/PRO 4.0/micro  .....  8 bit stereo (max 22kHz)');
  1118.     writeln(' 4) Soundblaster 16/16 ASP                 ..... 16 bit stereo (max 45kHz)');
  1119.     repeat c:=readkey; until (c in ['0','1','2','3','4']);
  1120.     case c of
  1121.       '0': exit;
  1122.       '1': SBNo:=1;
  1123.       '2': SBNo:=3;
  1124.       '3': SBNo:=4; { also 2,5 }
  1125.       '4': SBNo:=6;
  1126.     end;
  1127.     writeln(#13#10' Soundblaster baseport 2X0h ?');
  1128.     write(' X = ');
  1129.     repeat c:=readkey; until (c in ['0'..'9']);
  1130.     writeln(c);
  1131.     dsp_addr:=$200+$10*(ord(c)-ord('0'));
  1132.     write(#13#10' 8 bit DMA channel (0,1,3) ? ');
  1133.     repeat c:=readkey; until (c in ['0','1','3']);
  1134.     writeln(c);
  1135.     dma_channel:=ord(c)-ord('0');
  1136.     if SBNo=6 then
  1137.       begin
  1138.         write(#13#10' 16 bit DMA (5,6,7) ? ');
  1139.         repeat c:=readkey; until (c in ['5','6','7']);
  1140.         writeln(c);
  1141.         DMA_16bitchannel:=ord(c)-ord('0');
  1142.       end;
  1143.     write(#13#10' IRQ (2,5,7) ? ');
  1144.     repeat c:=readkey; until (c in ['2','5','7']);
  1145.     writeln(c);
  1146.     IRQ_No:=ord(c)-ord('0');
  1147.     forceto(SBNo,dma_channel,dma_16bitchannel,IRQ_No,dsp_addr);
  1148.     InputSoundblasterValues:=true;
  1149.   end;
  1150.  
  1151. procedure check_samplerate(var rate:word;var stereo:boolean);
  1152.   begin
  1153.     stereo:=stereo and stereo_possible;
  1154.     if rate<4000 then rate:=4000;
  1155.     if stereo then
  1156.        begin
  1157.          if rate>maxstereorate then rate:=maxstereorate;
  1158.        end
  1159.     else
  1160.       if rate>maxmonorate then rate:=maxmonorate;
  1161.   end;
  1162.  
  1163. begin
  1164.   SB_Detect:=False;
  1165.   DSPIRQ_Detect:=false;
  1166.   DSPADR_Detect:=false;
  1167.   DMACHN_Detect:=False;
  1168.   MIXER_Detect:=False;
  1169.   stereo_possible:=false;
  1170.   _16Bit_possible:=false;
  1171.   STEREO:=False;_16Bit:=False;signeddata:=false;
  1172.   SBVersHi:=0;SBVersLo:=0;
  1173.   SBno:=0;
  1174.   IRQ_No:=7;
  1175.   DSP_Addr:=$220;
  1176.   DMA_Channel:=1;
  1177.   DMA_16Bitchannel:=5;
  1178. end.
  1179.